import pandas as pd
import numpy as np
from scipy import signal
from scipy.ndimage import gaussian_filter1d
import matplotlib.pyplot as plt
import seaborn as sns
from datetime import datetime, timedelta
import warnings

warnings.filterwarnings('ignore')

# 设置中文字体和样式
plt.rcParams['font.sans-serif'] = ['SimHei', 'DejaVu Sans', 'Microsoft YaHei']
plt.rcParams['axes.unicode_minus'] = False
sns.set_style("whitegrid")
plt.rcParams['figure.figsize'] = [12, 8]


def enhance_holiday_data_low_volatility(input_file, output_file):
    """
    处理数据：突出节假日特征，大幅降低波动性
    """

    print("🔍 开始读取原始数据...")
    # 读取数据
    df = pd.read_csv(input_file)
    df['ds'] = pd.to_datetime(df['ds'])

    print(f"📊 原始数据统计:")
    print(f"   - 数据点数: {len(df)}")
    print(f"   - 平均值: {df['y'].mean():.2f}")
    print(f"   - 标准差: {df['y'].std():.2f}")
    print(f"   - 变异系数: {(df['y'].std() / df['y'].mean()) * 100:.2f}%")

    # 保存原始数据
    original_data = df.copy()

    # 第一步：多重平滑处理（大幅降低波动性）
    print("🔄 进行多重数据平滑处理...")

    # 方法1：Savitzky-Golay滤波器
    df['y_sg'] = signal.savgol_filter(df['y'], window_length=15, polyorder=2)

    # 方法2：高斯滤波
    df['y_gaussian'] = gaussian_filter1d(df['y'], sigma=3)

    # 方法3：移动平均
    df['y_ma_7'] = df['y'].rolling(window=7, center=True, min_periods=1).mean()
    df['y_ma_15'] = df['y'].rolling(window=15, center=True, min_periods=1).mean()

    # 方法4：指数加权移动平均
    df['y_ewma'] = df['y'].ewm(span=10, adjust=False).mean()

    # 组合平滑结果（加权平均）
    df['y_smoothed'] = (
            0.3 * df['y_sg'] +
            0.3 * df['y_gaussian'] +
            0.2 * df['y_ma_7'] +
            0.2 * df['y_ewma']
    )

    # 第二步：识别并增强节假日特征
    print("🎄 增强节假日特征...")

    holidays_config = {
        'childrens_day_2024': {
            'date': pd.Timestamp('2024-06-01'),
            'pre_days': 12,  # 提前12天开始影响
            'post_days': 6,  # 节后6天结束影响
            'peak_boost': 2.5  # 峰值增强2.5倍
        },
        'childrens_day_2025': {
            'date': pd.Timestamp('2025-06-01'),
            'pre_days': 14,
            'post_days': 7,
            'peak_boost': 2.8
        },
        'christmas_2024': {
            'date': pd.Timestamp('2024-12-25'),
            'pre_days': 25,  # 提前25天开始影响
            'post_days': 12,  # 节后12天结束影响
            'peak_boost': 3.0  # 峰值增强3.0倍
        },
        'newyear_2025': {
            'date': pd.Timestamp('2025-01-01'),
            'pre_days': 8,
            'post_days': 4,
            'peak_boost': 2.0
        }
    }

    # 创建节假日增强因子（更平滑的增强曲线）
    df['holiday_boost'] = 1.0

    for holiday_name, config in holidays_config.items():
        holiday_date = config['date']
        window_start = holiday_date - timedelta(days=config['pre_days'])
        window_end = holiday_date + timedelta(days=config['post_days'])

        mask = (df['ds'] >= window_start) & (df['ds'] <= window_end)
        days_from_holiday = (df['ds'] - holiday_date).dt.days

        # 使用更宽的高斯函数创建平滑的增强曲线
        sigma = config['pre_days'] / 1.5  # 更宽的曲线
        boost_values = 1 + (config['peak_boost'] - 1) * np.exp(-(days_from_holiday ** 2) / (2 * sigma ** 2))

        # 对增强因子本身也进行平滑
        boost_values_smoothed = gaussian_filter1d(boost_values, sigma=2)
        df.loc[mask, 'holiday_boost'] = np.maximum(df.loc[mask, 'holiday_boost'], boost_values_smoothed[mask])

    # 对整个增强因子序列进行最终平滑
    df['holiday_boost'] = gaussian_filter1d(df['holiday_boost'], sigma=1.5)

    # 第三步：应用节假日增强
    df['y_enhanced'] = df['y_smoothed'] * df['holiday_boost']

    # 第四步：后处理
    df['y_enhanced'] = df['y_enhanced'].clip(lower=0)  # 确保非负

    # 对最终结果进行轻微平滑
    df['y_enhanced'] = gaussian_filter1d(df['y_enhanced'], sigma=1.0)
    df['y_enhanced'] = df['y_enhanced'].round().astype(int)  # 取整

    # 保持总体数据量基本不变
    total_original = df['y'].sum()
    total_enhanced = df['y_enhanced'].sum()
    if total_enhanced > 0:
        adjustment_factor = total_original / total_enhanced
        df['y_enhanced'] = (df['y_enhanced'] * adjustment_factor).round().astype(int)

    # 最终平滑处理
    df['y_enhanced'] = df['y_enhanced'].rolling(window=5, center=True, min_periods=1).mean()
    df['y_enhanced'] = df['y_enhanced'].round().astype(int)

    # 第五步：创建节假日标记特征
    df['is_childrens_day_period'] = 0
    df['is_christmas_period'] = 0
    df['is_holiday_period'] = 0

    for holiday_name, config in holidays_config.items():
        holiday_date = config['date']
        window_start = holiday_date - timedelta(days=config['pre_days'])
        window_end = holiday_date + timedelta(days=config['post_days'])

        mask = (df['ds'] >= window_start) & (df['ds'] <= window_end)

        if 'childrens_day' in holiday_name:
            df.loc[mask, 'is_childrens_day_period'] = 1
        elif 'christmas' in holiday_name:
            df.loc[mask, 'is_christmas_period'] = 1

        df.loc[mask, 'is_holiday_period'] = 1

    print("✅ 数据处理完成!")
    print(f"📊 增强后数据统计:")
    print(f"   - 平均值: {df['y_enhanced'].mean():.2f}")
    print(f"   - 标准差: {df['y_enhanced'].std():.2f}")
    print(f"   - 变异系数: {(df['y_enhanced'].std() / df['y_enhanced'].mean()) * 100:.2f}%")

    # 计算波动性降低效果
    original_cv = (original_data['y'].std() / original_data['y'].mean()) * 100
    enhanced_cv = (df['y_enhanced'].std() / df['y_enhanced'].mean()) * 100
    reduction = ((original_cv - enhanced_cv) / original_cv) * 100

    print(f"📉 波动性降低: {reduction:.1f}%")

    # 保存结果
    output_df = df[['ds', 'y_enhanced', 'is_childrens_day_period', 'is_christmas_period', 'is_holiday_period']]
    output_df.columns = ['ds', 'y', 'is_childrens_day_period', 'is_christmas_period', 'is_holiday_period']
    output_df.to_csv(output_file, index=False)

    print(f"💾 增强后的数据已保存到: {output_file}")

    # 生成分析图表
    generate_low_volatility_analysis(original_data, df, holidays_config)

    return df


def generate_low_volatility_analysis(original_df, enhanced_df, holidays_config):
    """生成低波动性分析图表"""

    print("🎨 生成低波动性分析图表...")

    # 创建综合对比图
    fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(2, 2, figsize=(16, 12))
    fig.suptitle('低波动性数据增强效果分析', fontsize=16, fontweight='bold')

    # 1. 整体对比
    ax1.plot(original_df['ds'], original_df['y'], 'b-', alpha=0.5, label='原始数据', linewidth=1)
    ax1.plot(enhanced_df['ds'], enhanced_df['y_enhanced'], 'r-', label='低波动数据', linewidth=2)

    for holiday_name, config in holidays_config.items():
        if 'childrens_day' in holiday_name:
            color = 'orange'
            label = '六一儿童节'
        elif 'christmas' in holiday_name:
            color = 'green'
            label = '圣诞节'
        else:
            color = 'purple'
            label = '元旦'

        ax1.axvline(x=config['date'], color=color, linestyle='--', alpha=0.7)

    ax1.set_title('整体数据对比', fontweight='bold')
    ax1.set_xlabel('日期')
    ax1.set_ylabel('出口数量')
    ax1.legend()
    ax1.grid(True, alpha=0.3)

    # 2. 波动性对比
    window = 7
    original_volatility = original_df['y'].rolling(window=window).std()
    enhanced_volatility = enhanced_df['y_enhanced'].rolling(window=window).std()

    ax2.plot(original_df['ds'], original_volatility, 'b-', label='原始数据波动性', alpha=0.7)
    ax2.plot(enhanced_df['ds'], enhanced_volatility, 'r-', label='低波动数据波动性', linewidth=2)
    ax2.set_title('7天移动标准差对比', fontweight='bold')
    ax2.set_xlabel('日期')
    ax2.set_ylabel('标准差')
    ax2.legend()
    ax2.grid(True, alpha=0.3)

    # 3. 2024年六一儿童节特写
    childrens_day_2024 = pd.Timestamp('2024-06-01')
    window_start = childrens_day_2024 - timedelta(days=20)
    window_end = childrens_day_2024 + timedelta(days=15)

    mask = (enhanced_df['ds'] >= window_start) & (enhanced_df['ds'] <= window_end)
    zoom_data = enhanced_df[mask].copy()

    ax3.plot(zoom_data['ds'], original_df.loc[mask, 'y'], 'bo-', label='原始数据', markersize=3, alpha=0.7)
    ax3.plot(zoom_data['ds'], zoom_data['y_enhanced'], 'ro-', label='低波动数据', markersize=4)
    ax3.axvline(x=childrens_day_2024, color='orange', linestyle='--', linewidth=2, label='六一儿童节')
    ax3.set_title('六一儿童节特征（低波动）', fontweight='bold')
    ax3.set_xlabel('日期')
    ax3.set_ylabel('出口数量')
    ax3.legend()
    ax3.grid(True, alpha=0.3)
    ax3.tick_params(axis='x', rotation=45)

    # 4. 2024年圣诞节特写
    christmas_2024 = pd.Timestamp('2024-12-25')
    window_start = christmas_2024 - timedelta(days=30)
    window_end = christmas_2024 + timedelta(days=20)

    mask = (enhanced_df['ds'] >= window_start) & (enhanced_df['ds'] <= window_end)
    zoom_data = enhanced_df[mask].copy()

    ax4.plot(zoom_data['ds'], original_df.loc[mask, 'y'], 'bo-', label='原始数据', markersize=3, alpha=0.7)
    ax4.plot(zoom_data['ds'], zoom_data['y_enhanced'], 'ro-', label='低波动数据', markersize=4)
    ax4.axvline(x=christmas_2024, color='green', linestyle='--', linewidth=2, label='圣诞节')
    ax4.set_title('圣诞节特征（低波动）', fontweight='bold')
    ax4.set_xlabel('日期')
    ax4.set_ylabel('出口数量')
    ax4.legend()
    ax4.grid(True, alpha=0.3)
    ax4.tick_params(axis='x', rotation=45)

    plt.tight_layout()
    plt.savefig('low_volatility_enhancement.png', dpi=300, bbox_inches='tight')
    plt.show()

    # 统计对比图
    fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(14, 6))

    # 分布对比
    ax1.hist(original_df['y'], bins=40, alpha=0.6, label='原始数据', color='blue', density=True)
    ax1.hist(enhanced_df['y_enhanced'], bins=40, alpha=0.6, label='低波动数据', color='red', density=True)
    ax1.set_title('数据分布对比', fontweight='bold')
    ax1.set_xlabel('出口数量')
    ax1.set_ylabel('密度')
    ax1.legend()
    ax1.grid(True, alpha=0.3)

    # 变异系数对比
    cv_values = [
        (original_df['y'].std() / original_df['y'].mean()) * 100,
        (enhanced_df['y_enhanced'].std() / enhanced_df['y_enhanced'].mean()) * 100
    ]
    labels = ['原始数据', '低波动数据']
    colors = ['blue', 'red']

    bars = ax2.bar(labels, cv_values, color=colors, alpha=0.7)
    ax2.set_title('变异系数对比', fontweight='bold')
    ax2.set_ylabel('变异系数 (%)')

    # 添加数值标签
    for bar, value in zip(bars, cv_values):
        ax2.text(bar.get_x() + bar.get_width() / 2, bar.get_height() + 1,
                 f'{value:.1f}%', ha='center', va='bottom')

    plt.tight_layout()
    plt.savefig('volatility_comparison.png', dpi=300, bbox_inches='tight')
    plt.show()

    # 生成处理报告
    generate_low_volatility_report(original_df, enhanced_df)


def generate_low_volatility_report(original_df, enhanced_df):
    """生成低波动性处理报告"""

    original_cv = (original_df['y'].std() / original_df['y'].mean()) * 100
    enhanced_cv = (enhanced_df['y_enhanced'].std() / enhanced_df['y_enhanced'].mean()) * 100
    reduction = ((original_cv - enhanced_cv) / original_cv) * 100

    report = []
    report.append("=" * 70)
    report.append("📊 低波动性数据增强报告")
    report.append("=" * 70)
    report.append(f"📅 处理时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
    report.append("")

    report.append("📈 处理效果统计:")
    report.append(f"   - 原始数据平均值: {original_df['y'].mean():.2f}")
    report.append(f"   - 低波动数据平均值: {enhanced_df['y_enhanced'].mean():.2f}")
    report.append(f"   - 原始数据标准差: {original_df['y'].std():.2f}")
    report.append(f"   - 低波动数据标准差: {enhanced_df['y_enhanced'].std():.2f}")
    report.append(f"   - 原始变异系数: {original_cv:.2f}%")
    report.append(f"   - 低波动变异系数: {enhanced_cv:.2f}%")
    report.append(f"   - 📉 波动性降低: {reduction:.1f}%")
    report.append("")

    report.append("🎯 采用的平滑技术:")
    report.append("   1. Savitzky-Golay滤波器 (window=15)")
    report.append("   2. 高斯滤波 (sigma=3)")
    report.append("   3. 移动平均 (窗口: 7天, 15天)")
    report.append("   4. 指数加权移动平均 (span=10)")
    report.append("   5. 多重平滑组合")
    report.append("")

    report.append("✅ 优势:")
    report.append("   - 大幅降低随机波动")
    report.append("   - 保持整体趋势不变")
    report.append("   - 节假日特征更加清晰")
    report.append("   - 更适合时间序列预测")
    report.append("")

    report.append("📁 生成文件:")
    report.append("   - holiday_enhanced_data_low_volatility.csv (低波动数据)")
    report.append("   - low_volatility_enhancement.png (增强效果图)")
    report.append("   - volatility_comparison.png (波动性对比图)")
    report.append("")
    report.append("🎯 下一步: 使用低波动数据进行预测，预计MAPE会显著改善")

    with open('low_volatility_enhancement_report.txt', 'w', encoding='utf-8') as f:
        f.write('\n'.join(report))

    print('\n'.join(report))
    print("💾 处理报告已保存到: low_volatility_enhancement_report.txt")


# 主程序
if __name__ == "__main__":
    input_file = "prophet-data-simulated-2025-09-05-factor.csv"
    output_file = "holiday_enhanced_data_low_volatility.csv"

    print("🚀 开始低波动性数据增强处理...")
    print("=" * 60)

    enhanced_data = enhance_holiday_data_low_volatility(input_file, output_file)

    print("=" * 60)
    print("🎉 低波动性数据增强完成！")
    print("=" * 60)